/*********************************************************************************
 *      Copyright:  (C) 2024 YunQi
 *                  All rights reserved.
 *
 *       Filename:  sht20.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(25/04/24)
 *         Author:  denglen <Dengleen@outlook.com>
 *      ChangeLog:  1, Release initial version on "25/04/24 16:09:25"
 *                 
 ********************************************************************************/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <linux/i2c-dev.h>
#include <linux/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>

#include "logger.h"
#include "sht20.h"


static inline void msleep(unsigned long ms);
static inline void dump_buf(const char *prompt, u_int8_t *buf, int size);
int sht2x_init(char *i2c_dev);
int sht2x_get_serialnumber(int fd, u_int8_t *serialnumber, int size);
int sht2x_get_temp_humidity(int fd, float *temp, float *rh);

int sht2x_get_temperature_humidity(float *temp, float *rh)
{
	int         fd;
	u_int8_t     serialnumber[8];


	fd = sht2x_init(DEV_i2C);
	if(fd < 0)
	{
		log_error("SHT2x initalize failure\n");
		close(fd);
		return -1;
	}

	if( sht2x_get_serialnumber(fd, serialnumber, 8) < 0)
	{
		log_error("SHT2x get serial number failure\n");
		close(fd);
		return -2;
	}

	if( sht2x_get_temp_humidity(fd, temp, rh) < 0)
	{
		log_error("SHT2x get temperature and relative humidity failure\n");
		close(fd);
		return -3;
	}
	log_info("Temperature=%f ºC relative humidity=%f\n", *temp, *rh);

	close(fd);
	return 0;
}

static inline void msleep(unsigned long ms)
{
	struct timespec cSleep;
	unsigned long   ulTmp;

	cSleep.tv_sec = ms / 1000;
	if(cSleep.tv_sec == 0)
	{
		ulTmp = ms * 10000;
		cSleep.tv_nsec = ulTmp * 100;
	}
	else
	{
		cSleep.tv_nsec = 0;
	}

	nanosleep(&cSleep, 0);
}

static inline void dump_buf(const char *prompt, u_int8_t *buf, int size)
{
	int             i;

	if( !buf )
	{
		return ;
	}

	if( prompt )
	{
		log_debug("%s ", prompt);
	}

	for(i=0; i<size; i++)
	{
		log_debug("%02x ", buf[i]);
	}
	log_debug("\n");

	return ;
}

int sht2x_softreset(int fd)
{
	u_int8_t             buf[4];

	if( fd<0 )
	{
		log_info("%s line [%d] %s() get invalid input argument\n", __FILE__, __LINE__, __func__);
		return -1;
	}

	memset(buf, 0, sizeof(buf));
	buf[0] = SOFTRESET;
	write(fd, buf, 1);

	msleep(50);

	return 0;
}

int sht2x_init(char *i2c_dev)
{
	int           fd;

	if( (fd = open(i2c_dev, O_RDWR)) < 0)
	{
		log_error("i2c device open failed: %s\n", strerror(errno));
		return -1;
	}

	ioctl(fd, I2C_TENBIT, 0);
	ioctl(fd, I2C_SLAVE, 0x40);

	if( sht2x_softreset(fd) < 0 )
	{
		log_error("SHT2x softreset failure\n");
		return -2;
	}
	return fd;
}

int sht2x_get_temp_humidity(int fd, float *temp, float *rh)
{
	u_int8_t             buf[4];

	if( fd<0 || !temp || !rh )
	{
		log_info("%s line [%d] %s() get invalid input argument\n", __FILE__, __LINE__, __func__);
		return -1;
	}

	memset(buf, 0, sizeof(buf));

	buf[0] = TRIGGER_TEMPERATERE_NO_HOLD;
	write(fd, buf, 1);

	msleep(85);

	memset(buf, 0, sizeof(buf));

	read(fd, buf, 3);
	//dump_buf("Temperature sample data: ", buf, 3);

	*temp = 175.72 * (((((int)buf[0]) << 8) + (buf[1] & 0xfc)) / 65536.0) - 46.85;

	memset(buf, 0, sizeof(buf));

	buf[0] = TRIGGER_HUMIDITY_NO_HOLD;
	write(fd, buf, 1);

	msleep(29);
	memset(buf, 0, sizeof(buf));

	read(fd, buf, 3);
	//dump_buf("Relative humidity sample data: ", buf, 3);

	*rh = 125 * (((((int) buf[0]) << 8) + (buf[1] & 0xfc)) / 65536.0) -6 ;
	return 0;
}

int sht2x_get_serialnumber(int fd, u_int8_t *serialnumber, int size)
{
	u_int8_t              buf[4];

	if( fd<0 || !serialnumber || size!=8)
	{
		log_info("%s line [%d] %s() get invalid input argument\n", __FILE__, __LINE__, __FILE__);
		return -1;
	}

	memset(buf, 0, sizeof(buf));
	buf[0] = 0xfa;
	buf[1] = 0x0f;
	write(fd, buf, 2);

	memset(buf, 0, sizeof(buf));
	read(fd, buf, 4);

	serialnumber[5] = buf[0];
	serialnumber[4] = buf[1];
	serialnumber[3] = buf[2];
	serialnumber[2] = buf[3];

	memset(buf, 0, sizeof(buf));
	buf[0] = 0xfc;
	buf[1] = 0xc9;
	write(fd, buf, 2);

	memset(buf, 0, sizeof(buf));
	read(fd, buf, 4);

	serialnumber[1] = buf[0];
	serialnumber[0] = buf[1];
	serialnumber[7] = buf[2];
	serialnumber[6] = buf[3];

	//dump_buf("SHT2x Serial number: ", serialnumber, 8);

	return 0;
}


int main()
{
        float temp=0;
        float rh=0;
        sht2x_get_temperature_humidity(&temp, &rh);
        printf("温度为：%f\n",temp);
        printf("湿度为: %f\n",rh);
        return 0;
}
